package com.molichuxing.gateway.bff.financial.services.impl;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.molichuxing.framework.dto.Paged;
import com.molichuxing.framework.dto.TabDto;
import com.molichuxing.framework.exception.BizException;
import com.molichuxing.framework.utils.DateUtil;
import com.molichuxing.framework.utils.DingTalkUtil;
import com.molichuxing.framework.utils.EmailUtil;
import com.molichuxing.gateway.bff.dealer.services.impl.DealerBffServiceImpl;
import com.molichuxing.gateway.bff.financial.convertor.Convert;
import com.molichuxing.gateway.bff.financial.entity.request.modify.OfflineAuditModifyVo;
import com.molichuxing.gateway.bff.financial.entity.response.OfflineInfoVo;
import com.molichuxing.gateway.bff.financial.services.OfflineAuditBffService;
import com.molichuxing.gateway.property.EmailSubjectEnum;
import com.molichuxing.gateway.property.EmailTemplateEnum;
import com.molichuxing.gateway.utils.TokenUtil;
import com.molichuxing.gateway.utils.entity.UserEntity;
import com.molichuxing.services.business.dto.request.modify.OfflineAuditBizModifyDto;
import com.molichuxing.services.business.dto.request.modify.OrderScheduleAuditModifyDto;
import com.molichuxing.services.business.dto.request.modify.OrderScheduleOfflineBizModifyDto;
import com.molichuxing.services.business.dto.request.modify.OrderScheduleOfflineModifyDto;
import com.molichuxing.services.business.dto.response.OrderScheduleOfflineBizDto;
import com.molichuxing.services.business.dto.response.UserBizDto;
import com.molichuxing.services.business.service.OfflineBizService;
import com.molichuxing.services.business.service.OrderScheduleBizService;
import com.molichuxing.services.business.service.UserBizService;
import com.molichuxing.services.contants.OrderConst;
import com.molichuxing.services.infrastructure.dto.request.create.InvoiceCreateDto;
import com.molichuxing.services.infrastructure.dto.response.DealerDetailDto;
import com.molichuxing.services.infrastructure.dto.response.DealerDto;
import com.molichuxing.services.infrastructure.dto.response.OfflineDto;
import com.molichuxing.services.infrastructure.dto.response.OfflineOrdersDto;
import com.molichuxing.services.infrastructure.dto.response.OrderDealerDetailBasicDto;
import com.molichuxing.services.infrastructure.dto.response.OrderExclusivelDto;
import com.molichuxing.services.infrastructure.dto.response.OrderScheduleDto;
import com.molichuxing.services.infrastructure.dto.response.RiskEmailDto;
import com.molichuxing.services.infrastructure.dto.response.StoreDto;
import com.molichuxing.services.infrastructure.dto.response.response.AccountDto;
import com.molichuxing.services.infrastructure.service.AccountService;
import com.molichuxing.services.infrastructure.service.BlacklistService;
import com.molichuxing.services.infrastructure.service.DealerDetailService;
import com.molichuxing.services.infrastructure.service.DealerService;
import com.molichuxing.services.infrastructure.service.InvoiceService;
import com.molichuxing.services.infrastructure.service.OfflineOrdersService;
import com.molichuxing.services.infrastructure.service.OfflineService;
import com.molichuxing.services.infrastructure.service.OrderDealerService;
import com.molichuxing.services.infrastructure.service.OrderExclusivelService;
import com.molichuxing.services.infrastructure.service.OrderScheduleService;
import com.molichuxing.services.infrastructure.service.RiskEmailService;
import com.molichuxing.services.infrastructure.service.StoreService;
import com.molichuxing.services.infrastructure.service.UserService;
import com.molichuxing.services.property.OfflineAuditStatusEnum;
import com.molichuxing.services.property.OfflineRepayTypeEnum;
import com.molichuxing.services.property.OrderScheduleStatusEnum;
import com.molichuxing.services.property.RiskEmailReceiveTypeEnum;
import com.molichuxing.services.property.RiskEmailTypeEnum;

/**
 * 还款审核相关bff
 *
 * @author zhaopenghui
 * @date 2019年8月30日
 */
@Service("offlineAuditBffService")
public class OfflineAuditBffServiceImpl implements OfflineAuditBffService {
    private static final Logger logger = LoggerFactory.getLogger(DealerBffServiceImpl.class);

    @Resource
    private OfflineBizService offlineBizService;
    @Resource
    private OfflineService offlineService;
    @Resource
    private OfflineOrdersService offlineOrdersService;
    @Resource
    OrderScheduleBizService orderScheduleBizService;
    @Resource
    TokenUtil tokenUtil;
    @Resource
    OrderExclusivelService orderExclusivelService;
    @Resource
    OrderScheduleService orderScheduleService;
    @Resource
    DealerDetailService dealerDetailService;
    @Resource
    StoreService storeService;
    @Resource
    InvoiceService invoiceService;
    @Resource
    AccountService accountService;
    @Resource
    OrderDealerService orderDealerService;
    @Resource
    DealerService dealerService;
    @Resource
    RiskEmailService riskEmailService;

	@Resource
	private UserBizService userBizService;

	@Resource
	private UserService userService;

	@Resource
	private BlacklistService blacklistService;

    @Value("${profiles.active.explain}")
    private String ACTIVE_EXPLAIN;

    @Value("${email_account}")
    private String emailAccount;

    @Value("${email_password}")
    private String emailPassword;
    @Value("${order.dealer.change.url}")
    private String ORDER_DEALER_CHANGE_URL;

    /**
     * 还款审核
     *
     * @param map
     * @param pageNum
     * @param pageSize
     * @return
     * @throws Exception
     */
    @Override
    public Paged<OfflineInfoVo> getOfflinePage(Map<String, Object> map, Integer pageNum, Integer pageSize) throws Exception {
        Object auditStatus = map.get("auditStatus");
        if (null == auditStatus) {
            return new Paged<OfflineInfoVo>();
        }

        Paged<OfflineDto> offlinePage = offlineService.getOfflinePage(map, pageNum, pageSize);
        List<OfflineDto> offlineDtoList = offlinePage.getList();
        if (null == offlineDtoList) {
            Paged<OfflineInfoVo> paged = new Paged<OfflineInfoVo>();
            return getPageTab(paged);
        }

        List<OfflineInfoVo> offlineInfoVoList = Convert.toOfflineVoList(offlineDtoList);
        Paged<OfflineInfoVo> paged = new Paged<OfflineInfoVo>(offlineInfoVoList, offlinePage.getTotal(), pageSize);
        return getPageTab(paged);
    }

    /**
     * 获取分页tab值
     *
     * @return
     * @throws Exception
     */
    private Paged<OfflineInfoVo> getPageTab(Paged<OfflineInfoVo> paged) throws Exception {
        Map<Integer, Integer> statusCountMap = offlineService.getCountByAuditStatus(null);
        List<TabDto> tabList = new ArrayList<>();
        for (OfflineAuditStatusEnum offlineAuditStatusEnum : OfflineAuditStatusEnum.values()) {
            int value = offlineAuditStatusEnum.getValue();
            String name = offlineAuditStatusEnum.getName();
            Integer count = 0;
            if (null != statusCountMap && statusCountMap.size() > 0) {
                count = statusCountMap.get(value);
            }
            if (null == count) {
                count = 0;
            }

            TabDto tabDto = new TabDto();
            tabDto.setName(name);
            tabDto.setType(value);
            tabDto.setCount(count);
            tabList.add(tabDto);
        }
        return paged.setTab(tabList);
    }

    /**
     * 还款审核
     *
     * @param offlineAuditModifyVo
     * @return
     * @throws Exception
     */
    @Override
    public Boolean modifyAuditStatus(OfflineAuditModifyVo offlineAuditModifyVo) throws Exception {
        //查询账号是否存在
        UserEntity currentLoginUser = tokenUtil.getUser();
        if (null == currentLoginUser) {
            throw new Exception("用户未登录");
        }

        Integer offlineId = offlineAuditModifyVo.getOfflineId();
        Integer auditStatus = offlineAuditModifyVo.getAuditStatus();
        OfflineDto offline = offlineService.getOffline(offlineId);
        if (null == offline) {
            throw new BizException("还款信息不存在");
        }

        LocalDateTime payTime = offline.getPayTime();
        String serialNumber = offline.getSerialNumber();
        Integer applyId = offline.getApplyId();
        List<Integer> scheduleIdList = offlineOrdersService.getScheduleIdList(offlineId);

        Map<Integer, OrderScheduleOfflineBizDto> orderScheduleOfflineMap = new HashMap<>();
        if (auditStatus != null && OfflineAuditStatusEnum.APPROVE.getValue() == auditStatus) {
            OrderScheduleOfflineModifyDto orderScheduleOfflineModifyDto = new OrderScheduleOfflineModifyDto();
            orderScheduleOfflineModifyDto.setIds(scheduleIdList);
            orderScheduleOfflineModifyDto.setPaySuccessTime(payTime);
            orderScheduleOfflineModifyDto.setRepayTerminal("op");
            orderScheduleOfflineMap = orderScheduleBizService
                    .modifyOrderScheduleByOffline(orderScheduleOfflineModifyDto);
            Integer repayType = offline.getRepayType();
            if (OfflineRepayTypeEnum.USER.getValue() == repayType) {
				// 发票
                createRepaymentInvoice(offline);
				// 移除黑名单
				blackList(offlineId);
            }
        } else if (auditStatus != null && OfflineAuditStatusEnum.REJECT.getValue() == auditStatus) {
            OrderScheduleAuditModifyDto orderScheduleAuditModifyDto = new OrderScheduleAuditModifyDto();
            orderScheduleAuditModifyDto.setAccountId(currentLoginUser.getAccountId());
            orderScheduleAuditModifyDto.setRealName(currentLoginUser.getRealName());
            orderScheduleAuditModifyDto.setScheduleIds(scheduleIdList);
            orderScheduleBizService.auditRejected(orderScheduleAuditModifyDto);
        }

        OfflineAuditBizModifyDto offlineAuditBizModifyDto = Convert.toOfflineAuditBizModifyDto(offlineAuditModifyVo);
        Map<Integer, OrderScheduleOfflineBizModifyDto> orderScheduleModifyDtoMap = Convert
                .toOrderScheduleOfflineMap(orderScheduleOfflineMap);
        Boolean modifyAuditStatusBoolean = offlineBizService.modifyAuditStatus(offlineAuditBizModifyDto, orderScheduleModifyDtoMap);

        AccountDto accountDto = accountService.getById(applyId);
        if ((modifyAuditStatusBoolean) && (OfflineAuditStatusEnum.APPROVE.getValue() == auditStatus)) {
            EmailUtil.sendMail(emailAccount, emailPassword, "线下还款通过审核通知", EmailSubjectEnum.OFFLINE_APPROVE.getName().replace("$【serialNumber】", serialNumber), accountDto.getAccount());
        }
        if ((modifyAuditStatusBoolean) && (OfflineAuditStatusEnum.REJECT.getValue() == auditStatus)) {
            EmailUtil.sendMail(emailAccount, emailPassword, "线下还款驳回审核通知", EmailSubjectEnum.OFFLINE_REJECT.getName().replace("$【serialNumber】", serialNumber), accountDto.getAccount());
        }
        getFirstPeriods(offlineId, scheduleIdList);
        return modifyAuditStatusBoolean;
    }

	/**
	 * 操作黑名单
	 * 
	 * @param offlineId
	 */
	private void blackList(Integer offlineId) {
		// 查询排期
		List<OfflineOrdersDto> offlineOrders = offlineOrdersService.getOfflineOrdersList(offlineId);
		if (offlineOrders == null || offlineOrders.isEmpty()) {
			return;
		}
		for (OfflineOrdersDto offlineOrdersDto : offlineOrders) {
			// 查询订单信息
			OrderExclusivelDto orderExclusivelDto = orderExclusivelService
					.getOrderExclusivel(offlineOrdersDto.getOrderCode());
			// 查询用户信息
			UserBizDto userBizDto = userBizService.getUser(orderExclusivelDto.getUserId());
			try {
				// 查询排期信息
				List<OrderScheduleDto> orderScheduleDtos = orderScheduleService
						.getOrderSchedule(offlineOrdersDto.getOrderCode());
				if (orderScheduleDtos == null || orderScheduleDtos.isEmpty()) {
					continue;
				}
				int overdueNum = 0;
				boolean isWipe = true;
				for (OrderScheduleDto orderScheduleDto : orderScheduleDtos) {
					if (OrderScheduleStatusEnum.NO.equals(orderScheduleDto.getStatus())) {
						// 未还款，判断当前是否逾期
						long overdueDay = DateUtil.getDaysDiff(orderScheduleDto.getPayableDate(), LocalDateTime.now());
						if (overdueDay > 0L) {
							// 还存在逾期未还
							isWipe = false;
							break;
						}
					} else if (OrderScheduleStatusEnum.ALREADY.equals(orderScheduleDto.getStatus())) {
						long overdueDay = DateUtil.getDaysDiff(orderScheduleDto.getPayableDate(),
								orderScheduleDto.getPaySuccessTime());
						if (overdueDay > 0L) {
							overdueNum += 1;
						}
					}
				}
				if (overdueNum < OrderConst.OVERDUE_ACCUMULATED && isWipe) {
					// 移除黑名单（线下还款咋整??）
					if (blacklistService.modifyBlacklist(userBizDto.getIdNumber())) {
						userService.modifyIsBlack(userBizDto.getId(), false);
					}
				}
			} catch (Exception e) {
				logger.error("订单(" + offlineOrdersDto.getOrderCode() + ")线下还款移除黑名单失败", e);
			}
		}
	}

    /**
     * 第一期
     *
     * @param offlineId
     * @param scheduleIdList
     * @throws Exception
     */
    private void getFirstPeriods(Integer offlineId, List<Integer> scheduleIdList) throws Exception {
        List<OrderScheduleDto> orderScheduleDtoList = orderScheduleService.getOrderScheduleDtoListById(scheduleIdList);
        if (null == orderScheduleDtoList || orderScheduleDtoList.size() < 1) {
            return;
        }

        Boolean firstBoolean = false;
        for (OrderScheduleDto orderScheduleDto : orderScheduleDtoList) {
            Integer periods = orderScheduleDto.getPeriods();
            if (periods != null && periods == 1) {
                firstBoolean = true;
                break;
            }
        }

        if (firstBoolean) {
            firstSendMsg(offlineId);
        }
    }


    /**
     * 发消息
     *
     * @param offlineId
     * @throws Exception
     */
    private void firstSendMsg(Integer offlineId) throws Exception {
        List<OfflineOrdersDto> offlineOrdersList = offlineOrdersService.getOfflineOrdersList(offlineId);
        OfflineOrdersDto offlineOrdersDto = offlineOrdersList.get(0);
        Long orderCode = offlineOrdersDto.getOrderCode();
        OrderDealerDetailBasicDto orderDealerDetailBasicDto = orderDealerService.getDetailBasic(orderCode);
        DealerDto dealerDto = dealerService.getDealerById(orderDealerDetailBasicDto.getDealerId());
        List<String> emails = null;
        emails = getEmail(RiskEmailTypeEnum.ORDER_DEALER_WAITING_FOR_DEPARTURE); // getRiskEmailList(RiskEmailEnum.ONE.getValue());
        if (null != emails) {
            EmailUtil.sendMail(emailAccount, emailPassword,
                    EmailSubjectEnum.BUSINESS_ORDER_AUDIT_PASS.getName()
                            .replace("$【name】", dealerDto.getShortName()),
                    EmailTemplateEnum.BUSINESS_ORDER_AUDIT_PASS.getTemplate()
                            .replace("$【name】", dealerDto.getShortName())
                            .replace("$【orderCode】", String.valueOf(orderCode)),
                    emails);
        } else {
            logger.error("商家订单首期支付 未配置发送邮件人员的邮箱信息");
        }

        // 钉钉
        DingTalkUtil.execute(ORDER_DEALER_CHANGE_URL,
                EmailTemplateEnum.BUSINESS_ORDER_AUDIT_PASS.getTemplate()
                        .replace("$【name】", dealerDto.getShortName())
                        .replace("$【orderCode】", String.valueOf(orderCode)));

    }

    /**
     * 获取邮件人信息
     *
     * @return
     */
    private List<String> getEmail(RiskEmailTypeEnum riskEmailTypeEnum) {
        List<RiskEmailDto> riskList = riskEmailService.getByType(riskEmailTypeEnum.getValue(), RiskEmailReceiveTypeEnum.EMAIL_RECIPIENT.getValue());
        List<String> list = null;
        if (null != riskList && !riskList.isEmpty()) {
            list = new ArrayList<>();
            for (RiskEmailDto dto : riskList) {
                list.add(dto.getEmail());
            }
        }
        return list;
    }

    /**
     * 还款支付发票
     *
     * @param offline
     */
    private void createRepaymentInvoice(OfflineDto offline) {
        try {
            Integer offlineId = offline.getOfflineId();
            String serialNumber = offline.getSerialNumber();
            List<OfflineOrdersDto> offlineOrdersList = offlineOrdersService.getOfflineOrdersList(offlineId);
            List<InvoiceCreateDto> invoiceCreateDtoList = new ArrayList<>();
            for (OfflineOrdersDto offlineOrdersDto : offlineOrdersList) {
                Long orderCode = offlineOrdersDto.getOrderCode();
                Integer scheduleId = offlineOrdersDto.getScheduleId();

                OrderExclusivelDto orderExclusivel = orderExclusivelService.getOrderExclusivel(orderCode);
                // 查询排期信息
                OrderScheduleDto orderScheduleDto = orderScheduleService.getOrderSchedule(scheduleId);
                // 查询门店信息
                StoreDto storeDto = storeService.getStoreById(orderExclusivel.getPlaceStoreId());
                // 查询经销商信息
                DealerDetailDto dealerDetailDto = dealerDetailService.getDealerDetailById(storeDto.getDealerId());

                InvoiceCreateDto invoiceCreateDto = Convert.toInvoiceCreateDto(offline, orderExclusivel, orderScheduleDto, dealerDetailDto);
                invoiceCreateDtoList.add(invoiceCreateDto);
            }
            createInvoice(invoiceCreateDtoList, serialNumber);
        } catch (Exception e) {
            String msg = "线下支付(流水编号：" + offline.getSerialNumber() + ")审核通过创建发票信息异常：";
            logger.error(msg, e);
            DingTalkUtil.exceptionSend(ACTIVE_EXPLAIN + msg + e.getMessage());
        }
    }

    /**
     * 生成发票信息
     *
     * @param invoiceCreateDtoList
     * @param serialNumber
     * @throws Exception
     */
    private void createInvoice(List<InvoiceCreateDto> invoiceCreateDtoList, String serialNumber) throws Exception {
        // 生成发票信息
        if (!invoiceService.createInvoiceList(invoiceCreateDtoList)) {
            logger.error("线下支付(流水编号：" + serialNumber + ")审核通过创建发票信息异常");
            DingTalkUtil.exceptionSend(ACTIVE_EXPLAIN + "线下支付(流水编号：" + serialNumber + ")审核通过创建发票信息异常");
        }
    }

}
